package com.sakiko.listener;

import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

import java.io.UnsupportedEncodingException;

// 消息的可靠性 - 消费者端 实验
@Component
@Slf4j
public class MyMessageListener {

    public static final String EXCHANGE_DIRECT = "sakiko.exchange.direct";
    public static final String ROUTING_KEY = "sakiko.routing.key.a";
    public static final String QUEUE_NAME = "sakiko.queue.direct01";

    // 修饰监听方法 声明 交换机、队列、绑定，没有则创建
    // declare = "true" 标识资源在直接使用，不在则创建。  ==> 在的话属性必须一致 【推荐 true
    // durable = "true" 标识声明一个持久化资源，服务器重启不丢 【推荐 true
    // autoDelete = "true" 标识声明一个自动删除的资源，长时间不适用，资源自动删除 【推荐 false
    // exclusive = "true" 标识声明一个排他队列，排他队列只限于当前连接使用，当前连接关闭，资源自动释放 【推荐 false
    // internal = "false" 标识声明一个内部资源，内部资源只给服务器使用，不能用于业务逻辑 【推荐 false
    @RabbitListener(
            // 设置绑定关系 可以有多个 @QueueBinding
            bindings = {
                    @QueueBinding(
                            // 队列
                            value = @Queue(value = QUEUE_NAME, declare = "true", durable = "true", autoDelete = "false", exclusive = "false"),
                            // 交换机
                            exchange = @Exchange(value = EXCHANGE_DIRECT, durable = "true", autoDelete = "false", internal = "false"),
                            // 配置路由键信息
                            key = {ROUTING_KEY}
                    )})
    public void processMessage(String dataString, Message message, Channel channel) throws Exception {
        // 获取消息的唯一标识
        long deliveryTag = message.getMessageProperties().getDeliveryTag();

        try {
            log.info("dataString=" + dataString);
            log.info("messageBODY=" + new String(message.getBody(), "UTF-8"));
            log.info("messagePROPERTIES=" + message.getMessageProperties().toString());
            log.info("channel=" + channel);
//            int i = 1 / 0; // 模拟业务逻辑失败
            log.info("成功部分业务逻辑...");
            // 手动进行确认
            channel.basicAck(deliveryTag, false); // 不进行多个确认，一个一个确认，multiple = “false”
        } catch (UnsupportedEncodingException e) {
            // 此次消息是否为重复投递
            Boolean redelivered = message.getMessageProperties().isRedelivered();
            if (!redelivered)
                // 不进行确认 requeue = true 标识回到原有队列，可以进行再次投递处理 requeue = false 不能再次投递，如果没有死信队列进行特殊处理，丢弃该消息
                channel.basicNack(deliveryTag, false, true); // 一般配合 计数器或 isRedelivered使用
            else
                // 二次投递不成功，直接拒绝 丢弃 or 死信队列处理
                channel.basicReject(deliveryTag, false);
            throw new RuntimeException(e);
        }
    }
}